package com.linciping.gradle.methodcodeinject

import org.objectweb.asm.ClassReader
import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.commons.AdviceAdapter

class SpendInjectMethodVisitor(
    classReader: ClassReader,
    private val lineStartLabelMap: Map<Label, Int>,
    private val methodName: String?,
    methodVisitor: MethodVisitor?,
    access: Int, descriptor: String?
) : AdviceAdapter(
    ASM7, methodVisitor,
    access, methodName, descriptor,
) {

    private val className = classReader.className
    private var codeSpendCount = 0
    private var labelOffset = 0

    override fun visitLabel(label: Label?) {
        super.visitLabel(label)
        val startLabel = findStartLabel(label)
        if (startLabel != null) {
            val methodInfo = "$className\$$methodName\$${startLabel.line}"
            visitLdcInsn(methodInfo)
            visitMethodInsn(
                INVOKESTATIC, "com/linciping/gradle/test/MethodCodeSpend",
                "codeSpend", "(Ljava/lang/String;)V", false
            )
            codeSpendCount++
            labelOffset = codeSpendCount * 5
        }
    }

    private fun findStartLabel(label: Label?): StartLabel? {
        if (label == null) return null
        val labelOffset = try {
            label.offset - labelOffset
        } catch (ex: Exception) {
            return null
        }
        for (startLabel in lineStartLabelMap.keys) {
            if (labelOffset == startLabel.offset) {
                return StartLabel(startLabel, lineStartLabelMap[startLabel]!!)
            }
        }
        return null
    }
}